package com.zisu.aradvertising.utils;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.zisu.aradvertising.config.OSSConfiguration;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@Configuration
@Component
public class OSSUtil {

    public static Logger log = LoggerFactory.getLogger(OSSUtil.class);

    @Autowired
    private OSSConfiguration ossConfiguration;

    @Autowired
    private OSS ossClient;

    /**
     * 上传文件到阿里云 OSS 服务器
     *
     * @param file     文件名
     * @param fileName 相对文件名
     * @return 文件的url
     */
    public String uploadFile(MultipartFile file, String fileName, int n) {
        try {
            String contentType = file.getContentType();
            // 注意：默认获取到的 image/jpeg 类型，在oss中直接访问是“下载”而非“预览”，
            //       所以应当改变为  image/jpg
            if ("image/jpeg".equals(contentType) || "image/png".equals(contentType)) {
                contentType = "image/jpg";
            }
            InputStream inputStream = file.getInputStream();
            // 设置对象
            ObjectMetadata objectMetadata = new ObjectMetadata();
            // 设置数据流里有多少个字节可以读取
            objectMetadata.setContentLength(inputStream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(contentType);
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            ossClient.putObject(ossConfiguration.getBucketName(), fileName, inputStream, objectMetadata);// 上传文件
            if (n == 0) {
                ossClient.setObjectAcl(ossConfiguration.getBucketName(), fileName, CannedAccessControlList.PublicRead);//设置公共读权限
            } else {
                ossClient.setObjectAcl(ossConfiguration.getBucketName(), fileName, CannedAccessControlList.Default);//设置私有权限
            }
        } catch (IOException e) {
            log.error("Error occurred: {}", e.getMessage(), e);
        }
        return ossConfiguration.getOssPath()+fileName;
    }

    public void uploadpicture(MultipartFile file, String fileName, int n) {
        try {
            String contentType = "image/jpg";
            // 注意：默认获取到的 image/jpeg 类型，在oss中直接访问是“下载”而非“预览”，
            //       所以应当改变为  image/jpg
            InputStream inputStream = file.getInputStream();
            // 设置对象
            ObjectMetadata objectMetadata = new ObjectMetadata();
            // 设置数据流里有多少个字节可以读取
            objectMetadata.setContentLength(inputStream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(contentType);
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            ossClient.putObject(ossConfiguration.getBucketName(), fileName, inputStream, objectMetadata);// 上传文件
            if (n == 0) {
                ossClient.setObjectAcl(ossConfiguration.getBucketName(), fileName, CannedAccessControlList.Default);//设置公共读权限
            } else {
                ossClient.setObjectAcl(ossConfiguration.getBucketName(), fileName, CannedAccessControlList.Default);//设置私有权限
            }
        } catch (IOException e) {
            log.error("Error occurred: {}", e.getMessage(), e);
        }
    }

    /**
     * 删除文件
     *
     * @param fileName 相对文件路径
     */
    public void deleteFile(String fileName) {
        try {
            ossClient.deleteObject(ossConfiguration.getBucketName(), fileName);
        } catch (Exception e) {
            log.error("Error occurred: {}", e.getMessage(), e);
        }
    }

    /**
     * 流式下载
     *
     * @param os         文件流
     * @param objectName 相对文件名
     */
    public void exportFile(OutputStream os, String objectName) {
        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流
        OSSObject ossObject = ossClient.getObject(ossConfiguration.getBucketName(), objectName);
        // 读取文件内容
        BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
        BufferedOutputStream out = new BufferedOutputStream(os);
        byte[] buffer = new byte[1024];
        int lenght;
        try {
            while ((lenght = in.read(buffer)) != -1) {
                out.write(buffer, 0, lenght);
            }
            out.flush();
            os.close();
            out.close();
        } catch (IOException e) {
            log.error("Error occurred: {}", e.getMessage(), e);
        }
    }

    /**
     * 获取 url
     *
     * @param filename
     * @return
     */
    public String getSingeNatureUrl(String filename) {
        Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 180);
        URL url = ossClient.generatePresignedUrl(ossConfiguration.getBucketName(), filename, expiration);
        if (url != null) {
            return url.toString();
        }
        return null;
    }

    /**
     * 判断文件是否存在
     *
     * @param fileName 相对文件路径
     * @return true/false
     */
    public boolean doesObjectExist(String fileName) {
        try {
            if (Strings.isEmpty(fileName)) {
                log.error("文件名不能为空");
                return false;
            } else {
                return ossClient.doesObjectExist(ossConfiguration.getBucketName(), fileName);
            }
        } catch (OSSException | ClientException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 查看 Bucket 中的 Object 列表
     *
     * @return 对象列表
     */
    public List<String> listObjects() {
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(ossConfiguration.getBucketName()).withMaxKeys(200);
        ObjectListing objectListing = ossClient.listObjects(listObjectsRequest);
        List<OSSObjectSummary> objectSummaries = objectListing.getObjectSummaries();
        return objectSummaries.stream().map(OSSObjectSummary::getKey).collect(Collectors.toList());
    }

    /**
     * 设置文件访问权限（这里默认设置为公共读权限）
     *
     * @param fileName 相对文件路径
     */
    public void setObjectAcl(String fileName) {
        ossClient.setObjectAcl(ossConfiguration.getBucketName(), fileName, CannedAccessControlList.PublicRead);
    }

    /**
     * OSS文件批量下载
     *
     * @param localPath 本地存储路径
     */
    public void fileBatchDownload(String localPath) {
        // 构造ListObjectsRequest请求
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(ossConfiguration.getBucketName());
        //Delimiter 设置为 “/” 时，罗列该文件夹下的文件
        listObjectsRequest.setDelimiter("/");
        //Prefix 设为某个文件夹名，罗列以此 Prefix 开头的文件
//        listObjectsRequest.setPrefix("test/");

        ObjectListing listing = ossClient.listObjects(listObjectsRequest);

        // 遍历所有Object:目录下的文件
        for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) {
            //key：fun/like/001.avi等，即：Bucket中存储文件的路径
            String key = objectSummary.getKey();
            //判断文件所在本地路径是否存在，若无，新建目录
            File file = new File(localPath + key);
            File fileParent = file.getParentFile();
            if (!fileParent.exists()) {
                fileParent.mkdirs();
            }
            //下载object到文件
            try {
                ossClient.getObject(new GetObjectRequest(ossConfiguration.getBucketName(), key), file);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.out.println("下载完成");
        // 关闭client
        ossClient.shutdown();
    }
}
